انتقل إلى المحتوى الرئيسي

صفحة عمليات النظام


صورة صفحة عمليات النظام

فايلات الفولدر

الفايلات
useSystemOperations.ts
SystemOperationCard.tsx
SystemOperationsView.tsx

useSystemOperations.ts

const backupMutation = useMutation({
mutationFn: backupRequest,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["backups"],
});

toast.success(t("successMessage"));
},
onError: (error) => {
const errorMessage = (error as any)?.response?.data?.message;
toast.error(t("errorMessage"), { description: `${errorMessage}` });
},
});
const handleBackup = () => {
backupMutation.mutate();
};
  • هاي دالتين الوظيفة مالتهن هو تنفيذ عملية ال backup وبالنسبة للكود مال تنفيذ التواصل ويا الباك حيكون هيج :
export const backupRequest = async () => {
const response = await axiosInstance.post("/database/backup", null, {
responseType: "blob",
});
const blob = response.data;
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "database_backup.sql";
a.click();
URL.revokeObjectURL(url);
return response.data;
};
  • هنا راح يرجع الي بال response : blob
  • وهذا راح نطلع منة البيانات ونحولها الى url
  • وبعدين راح ندخلها بداخل Tag
  • ونسوي الة تنزيل تلقائي وراح ينزل عند المستخدم بالمتصفح
  • واخير شي احرر ال temparary blob علمود لا يصير عندك Memory leaks
const restoreMutation = useMutation({
mutationFn: () => {
return restoreRequest(uploadedFile, setProgress);
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["restores"],
});
setProgress(undefined);
toast.success(t("successMessage"));
},
onError: (error) => {
const errorMessage = (error as any)?.response?.data?.message;
toast.error(t("errorMessage"), { description: `${errorMessage}` });
},
});

const handleRestore = () => {
restoreMutation.mutate();
};
  • بالنسبة الهاي فهاي راح تسوي عملية الاسترجاع طبعا لازم ترسل الها فايل الي نزلتة قبل شوية وايضا راح ينحط وياها ال setPrgress علمود يسوي تتبع شكد وصل التحميل ويعرض النتيجة بالمتصفح
  • بالنسبة للكود مال التواصل ويا الباك ايند فهو :
export const restoreRequest = async (
file: File | undefined,
onProgress: (progress: number) => void
) => {
if (
file?.type !== "application/octet-stream" &&
file?.type !== "application/sql" &&
!file?.name.endsWith(".sql")
) {
throw new Error("Please select a valid .sql file.");
}
const formData = new FormData();
formData.append("backupFile", file);

const response = await axiosInstance.post("/database/restore", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
onUploadProgress: (progressEvent) => {
const progressPercentage =
Math.round(progressEvent.loaded * 100) /
(progressEvent.total ? progressEvent.total : 1);
onProgress(progressPercentage);
},
});
return response.data;
};
  • اول شي راح يستقبل شغلتين الي هنة الفايل والدالة مال التتبع
  • ثاني شي راح يجيك البيانات الي اجتي هل هي فايل ومن نوع SQL فاذا لا راح يشمر ايررور
  • وراح تنرسل البيانات على شكل فورم
  • اخير شي عدنة ال onUploadProgress الي هي دالة راح تتبع التقدم الي صار الحد هسة وراح تحط بال onProgress
const resetCounterMutation = useMutation({
mutationFn: resetOrdersCounter,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["resetCounter"],
});
toast.success(t("successMessage"));
},
onError: (error) => {
const errorMessage = (error as any)?.response?.data?.message;
toast.error(t("errorMessage"), { description: `${errorMessage}` });
},
});

const handleResetCounter = () => {
resetCounterMutation.mutate();
};
  • هاي الدالة هي مجرد راح نسوي هنا بوست وراح تصفر العداد الي موجود بالواجهة مال المستخدم

SystemOperationCard.tsx

interface SystemOperationCardProps {
titleKey: string;
descriptionKey: string;
dialog: {
titleKey: string;
descriptionKey: string;
confirmLabelKey: string;
cancelLabelKey: string;
};
buttonLabelKey: string;
onConfirm: () => void;
}

//

const SystemOperationCard: React.FC<SystemOperationCardProps> = ({
titleKey,
descriptionKey,
dialog,
buttonLabelKey,
onConfirm,
}) => {
const { t } = useTranslation();

return (
<div className="flex flex-col gap-5 border w-fit p-5 rounded-xl">
<h1 className="text-2xl font-bold">{t(titleKey)}</h1>
<p className="text-lg">{t(descriptionKey)}</p>
<ConfirmButton
className="w-fit "
confirmTitle={t(dialog.titleKey)}
confirmDescription={t(dialog.descriptionKey)}
confirmLabel={t(dialog.confirmLabelKey)}
cancelLabel={t(dialog.cancelLabelKey)}
onClick={onConfirm}
>
<Button>{t(buttonLabelKey)}</Button>
</ConfirmButton>
</div>
);
};
  • عدنة هاي الدالة راح تستقبل SystemOperationCardProps type من ال interface والي هاي راح تعرض النة الكارد مال الاسترجاع وتصفير القوائم
  • راح تعبر البيانات والدوال على الcomponent ويا ال re-usable ConfirmButton

SystemOperationsView.tsx

<SystemOperationCard
titleKey="pages.management.systemOperations.backup.title"
descriptionKey="pages.management.systemOperations.backup.description"
dialog={{
cancelLabelKey: "pages.management.systemOperations.backup.dialog.cancel",
confirmLabelKey: "pages.management.systemOperations.backup.dialog.confirm",
descriptionKey: "pages.management.systemOperations.backup.dialog.description",
titleKey: "pages.management.systemOperations.backup.dialog.title",
}}
buttonLabelKey="pages.management.systemOperations.backup.buttonLabel"
onConfirm={handleBackup}
i18nIsDynamicList
/>
//
<SQLFileInput
control={restoreInputMethods.control}
handleFileChange={setUploadedFile}
name="attachement"
progress={progress}
onSubmit={handleRestore}
/>
  • اول component شفت الكود مالتة الفوك وشنو راح يستقبل
  • ثاني واحد هو ال SQLFileInput
//SQLFileInput
type FileInputProps<T extends FieldValues> = {
name: Path<T>;
control: Control<T>;
label?: string;
hide?: boolean;
className?: string;
disabled?: boolean;
description?: string;
progress?: number;
handleFileChange: (file: File | undefined) => void;
onSubmit: () => void;
};
  • هنا راح تستقبل الدالة هذني البارميترات والدوال والي بيهن اختياري والي اجبارية
//SQLFileInput
<Input
type="file"
id={name}
accept=".sql"
onChange={(e) => {
const file = e.target.files?.[0];
if (file && file.name.toLowerCase().endsWith(".sql")) {
handleFileChange(file);
setSelectedFile(file);
field.onChange(file as PathValue<T, Path<T>>);
} else {
form.setError(name, {
message: t(
"pages.management.systemOperations.restore.SQLFileInput.invalidSqlFile"
),
});
field.onChange(undefined as any);
}
}}
className="hidden"
/>
  • هذا الانبوت راح يستقبل بس فايلات من نوع SQL
  • ثم راح يجيك اذا اكو فايل تم اختياره لو لا وهل منتهي ويا .sql
  • اذا اي فراح يحط القيمة مال الفايل المختار بال setters
  • اذا لا فراح يرجع ايررور للمستخدم
  • باقي الصفحة مال SystemOperationsView هي مجرد عرض للصفحة ولوجك بسيط